package org.flyan.ffsm.test.demo;

import cn.hutool.core.map.MapUtil;
import org.flyan.ffsm.core.event.Event;
import org.flyan.ffsm.core.arg.Args;
import org.flyan.ffsm.core.sm.StateMachine;
import org.flyan.ffsm.core.sm.StateMachineBuilder;
import org.flyan.ffsm.core.state.State;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 状态机示例： 密码输入流程的简单状态机
 * <p>
 * 如果使用流程图来看，这是一个单向的流程，例如密码是 "9527"，它的流程图如下
 * (9) -> (5) -> (2) -> (7) -> (密码正确解锁成功)
 *
 * @author flyan
 * @version 1.0
 * @date 6/28/22
 */
public class PasswordInputDemo {

    /**
     * 密码，以 # 结尾
     *
     * @param pwd
     */
    public void runTest(String pwd) {
        if(pwd == null || pwd.isEmpty()) {
            return;
        }

        /* 状态表 */
        Map<String, State<String, String>> stateDict = new HashMap<>(pwd.length() + 1);
        List<String> stateKeys = new ArrayList<>(pwd.length() + 1);
        State<String, String> stateNone = new State<>("[NONE]");
        stateKeys.add("[NONE]");
        stateDict.put("[NONE]", stateNone);
        for (char c : pwd.toCharArray()) {
            stateKeys.add(c + "");
            stateDict.put(c + "", new State<>(c + ""));
        }

        /* 构建状态机 */
        StateMachineBuilder<String, String> builder = StateMachineBuilder.builder();
        for (int i = 1; i < stateKeys.size(); i++) {
            String prev = stateKeys.get(i - 1);
            String curr = stateKeys.get(i);
            builder.event(stateDict.get(prev), new Event<>(curr, ((event, args) -> {
                System.out.println(args.getArg("user") + ": " + event.getCurrState().getStateTag() + "->" + curr);
                return stateDict.get(curr);
            })));
        }
        StateMachine<String, String> machine = builder
                .states(stateDict.get(stateKeys.get(stateKeys.size() - 1)))
                .build();
        machine.getStateTable().forEach((k, v) -> {
            System.out.println(k + ", " + v.getEventTable());
        });

        /* 获取用户输入并使用状态机检查 */
        Scanner scanner = new Scanner(System.in);
        String line;
        Args loginUserArgs = new Args(MapUtil.of("user", "flyan"));
        while (!"#".equals(line = scanner.nextLine())) {
            /* 模拟用户输入队列 */
            List<String> userInputSeq = Arrays.stream(line.split("")).collect(Collectors.toList());

            State<String, String> currState = stateNone;
            /* 处理每次的用户输入，使用状态机检查 */
            for (String input : userInputSeq) {
                currState = machine.eventHappen(currState, input, loginUserArgs);
            }

            if (currState == null) {
                /* 到达一个不可达状态，解锁失败 */
                System.out.println("unlock failed...");
            } else {
                /* 到达可达状态，打印信息看看 */
                System.out.println(currState);
                if (currState.isFinal()) {
                    /* 到达最终状态，说明解锁成功！ */
                    System.out.println("unlock!");
                }
            }
            System.out.println("---------------------------");
        }
    }

        public static void main(String[] args) {
            new PasswordInputDemo().runTest("147258#");
        }

}
